package com.gitee.wsl.ext.reflect

import kotlin.reflect.KType

import kotlin.reflect.KClass
import kotlin.reflect.KClassifier
import kotlin.reflect.KTypeParameter
import kotlin.reflect.KTypeProjection

actual fun KType.withNullability(nullable: Boolean): KType {
    if (nullable == isMarkedNullable) return this
    return KTypeImpl1(classifier, arguments, nullable)
}
 actual val KClass<*>.qualifiedNameForComparison: String?
    get() = qualifiedName

internal class KTypeImpl1(
    override val classifier: KClassifier?,
    override val arguments: List<KTypeProjection>,
    override val isMarkedNullable: Boolean
) : KType {

    override fun equals(other: Any?) =
        other is KTypeImpl &&
                this.classifier == other.classifier &&
                this.arguments == other.arguments &&
                this.isMarkedNullable == other.isMarkedNullable

    override fun hashCode(): Int {
        return (classifier?.hashCode() ?: 0) * 31 * 31 + this.arguments.hashCode() * 31 + if (isMarkedNullable) 1 else 0
    }

    override fun toString(): String {
        val classifierString = when (classifier) {
            is KClass<*> -> classifier.qualifiedName ?: classifier.simpleName
            is KTypeParameter -> classifier.name
            else -> null
        } ?: return "(non-denotable type)"

        return buildString {
            append(classifierString)

            if (arguments.isNotEmpty()) {
                append('<')

                arguments.forEachIndexed { index, argument ->
                    if (index > 0) append(", ")

                    append(argument)
                }

                append('>')
            }

            if (isMarkedNullable) append('?')
        }
    }
}


 actual class KTypeImpl
actual constructor(
    actual override val classifier: KClassifier?,
    actual override val arguments: List<KTypeProjection>,
    actual override val isMarkedNullable: Boolean,
    actual override val annotations: List<Annotation>,
) : KType, EitherNetKType {
    private val impl = EitherNetKTypeImpl(classifier, arguments, isMarkedNullable, annotations)

    override fun equals(other: Any?) = impl == other

    override fun hashCode() = impl.hashCode()

    override fun toString() = impl.toString()
}